package com.nopay.dxdwphone.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Environment;
import android.telephony.TelephonyManager;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.UUID;

/**
 * 设备ID管理器
 * author：jun
 * date：2021/7/3
 */
public class DeviceIdManager {

    private static final String TAG = DeviceIdManager.class.getSimpleName();

    @SuppressLint("HardwareIds")
    public static String getId(Context context) {
        // 1. 读取缓存文件
        String id = read(context);
        if(!isNull(id)) return id;

        // 2. 读取设备信息
        StringBuffer sb = new StringBuffer();

        // 2.1 读取IMIE
        try {
            TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            String deviceId = telManager.getDeviceId();
            if(!isNull(deviceId)) sb.append(deviceId);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 2.2 读取本地设备的MAC地址
        sb.append(getLocalMac(context));

        // 3. 如果设备信息未获取到，自动生成
        if(sb.length() == 0) {
            UUID uuid = UUID.randomUUID();
            sb.append(uuid.toString().replace("-", ""));
        }

        // 4. 对设备ID进行加密保存
        id = MD5(sb.toString());
        write(context, id);
        return id;
    }

    /**
     * 从缓存文件中读取设备ID
     * @param context 上下文
     * @return 设备ID
     */
    private static String read(Context context) {
        File cache = getCacheFile(context);
        if (cache.exists()) {
            StringBuilder sb = new StringBuilder();
            try {
                FileInputStream fis = new FileInputStream(cache);
                InputStreamReader isReader = new InputStreamReader(fis, StandardCharsets.UTF_8);
                Reader in = new BufferedReader(isReader);
                int i;
                while ((i = in.read()) > -1) {
                    sb.append((char) i);
                }
                in.close();
                return sb.toString();
            } catch (IOException e) {
                Log.e(TAG, "READ FAILED: cache file");
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将设备ID写入缓存文件
     * @param context 上下文
     * @param id 设备ID
     */
    private static void write(Context context, String id) {
        File cache = getCacheFile(context);
        try {
            if (!cache.exists()) {
                boolean success = cache.createNewFile();
                if(success) {
                    Log.e(TAG, "CREATE SUCCESS: cache file");
                } else {
                    Log.e(TAG, "CREATE FAILED: cache file");
                }
            }
            FileOutputStream fos = new FileOutputStream(cache);
            Writer out = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
            out.write(id);
            out.close();
        } catch (IOException e) {
            Log.e(TAG, "WRITE FAILED: cache file");
            e.printStackTrace();
        }
    }

    // 缓存目录
    private static final String DEVICE_ID_CACHE_DIR = "1688km/cache";
    // 缓存名称
    private static final String DEVICE_ID_CACHE_FILE_NAME = "DEVICE_ID.LOG";

    /**
     * 获取缓存文件
     * @param context 上下文
     * @return 缓存文件对象
     */
    private static File getCacheFile(Context context) {
        // 1. SD卡是否可用
        boolean canUsedSD = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

        // 2. 创建缓存目录
        File cacheDir = new File(canUsedSD ? Environment.getExternalStorageDirectory() : context.getFilesDir(), DEVICE_ID_CACHE_DIR);
        if(!cacheDir.exists()) {
            boolean success = cacheDir.mkdirs();
            if(success) {
                Log.e(TAG, "CREATE SUCCESS: cache dir");
            } else {
                Log.e(TAG, "CREATE FAILED: cache dir");
            }
        }

        // 3. 创建缓存文件
        return new File(cacheDir, DEVICE_ID_CACHE_FILE_NAME);
    }

    /**
     * MD5加密
     * @param id 需要加密的设备ID
     * @return 加密后的设备ID
     */
    private static String MD5(String id) {
        String[] HEX_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] md5Bytes = md5.digest(id.getBytes());
            StringBuffer md5Buffer = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; i++) {
                md5Buffer.append(HEX_DIGITS[md5Bytes[i] >>> 4 & 0xf]);
                md5Buffer.append(HEX_DIGITS[md5Bytes[i] & 0xf]);
            }
            return md5Buffer.toString().toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return id;
    }

    /**
     * 是否为空
     * @param id 设备ID
     * @return true/false
     */
    private static boolean isNull(String id) {
        return id == null || "".equals(id);
    }

    /**
     * 获取本地MAC
     * @param context 上下文
     * @return MAC
     */
    private static String getLocalMac(Context context) {
        try {
            NetworkInterface network = NetworkInterface.getByName("eth1");
            if (network == null) network = NetworkInterface.getByName("wlan0");
            if (network == null) return "";
            byte[] macBytes = network.getHardwareAddress();
            StringBuffer buffer = new StringBuffer();
            for (byte b : macBytes) {
                buffer.append(String.format("%02X:", b));
            }
            if (buffer.length() > 0) buffer.deleteCharAt(buffer.length() - 1);
            return buffer.toString();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return "";
    }
}
